/* 09-prod-cons.c

   Producer-consumer co-routining.  There are five producers and four 
   consumers.  Two successors put consecutive numbers into their respective 
   streams.  Two times consumers multiply all consumed numbers by 5 and 3
   respectively and put the results into their streams.  A merge consumer
   merges the two stream created by the times producers.  A consumer prints 
   tokens from the merge stream.  This  illustrates that producer-consumer 
   relationships can be formed into complex networks.
*/
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/kthread.h>
#include<linux/sched.h>

int idcnt = 1;

/* One of these per stream - holds the mutex lock and the condition var */
/*
typedef struct stream_struct {
   struct stream_struct *next;
   pthread_mutex_t lock;
   pthread_cond_t notifier;
   void *value;
   int available;
   void *args;             /* arguments for the producing stream */
   int id;
} Stream;
*/

/* List of streams that a producer consumes tokens from (prod)
   plus the producer's stream (self) 
*/
  /*
typedef struct {
   Stream *prod, *self;
} Args;
  */

/* return 'value' which should have a value from a call to put */
  /*
void *get(void *stream) {
   void *ret;

   int available = ((Stream*)stream)->available;
   pthread_mutex_t *lock = &((Stream*)stream)->lock;
   pthread_cond_t *notifier = &((Stream*)stream)->notifier;
   
   pthread_mutex_lock(lock);
   if (available == 0) pthread_cond_wait(notifier, lock); 
   ((Stream*)stream)->available = 0;
   ret = ((Stream*)stream)->value;
   pthread_cond_signal(notifier);
   pthread_mutex_unlock(lock);

   return ret;
}
  */

/* 'value' is the value to move to the consumer */
  /*
void put(void *stream, void *value) {
   int available = ((Stream*)stream)->available;
   pthread_mutex_t *lock = &((Stream*)stream)->lock;
   pthread_cond_t *notifier = &((Stream*)stream)->notifier;
   
   pthread_mutex_lock(lock);
   if (available == 1) pthread_cond_wait(notifier, lock); 
   ((Stream*)stream)->value = value;
   ((Stream*)stream)->available = 1;
   pthread_cond_signal(notifier);
   pthread_mutex_unlock(lock);

   return;
}
  */

  /*
void *successor (void *streams) {
   Stream *self = ((Args*)streams)->self;
   int id = ((Args*)streams)->self->id;
   int i;
   
   for (i=1 ; ; i++) {
      printk(KERN_INFO "Successor(%d): sending %d\n", id, i);
      put(self, (void*)i);
      printk(KERN_INFO "Successor(%d): sent %d\n", id, i);
   }
}
  */

  /*
void *times (void *streams) {
   Stream *self = ((Args*)streams)->self;
   Stream *prod = ((Args*)streams)->prod;
   int i, value, in;
   
   printk(KERN_INFO "Times(%d) connected to Successor (%d)\n", 
	  self->id, prod->id);
   while (1) {
      int in = (int)get(prod);
      value = in * (int)(self->args);
      printk(KERN_INFO "\t\tTimes(%d): got %d from Successor %d\n",self->id,in,prod->id);
      put(self, (void*)value);
      printk(KERN_INFO "\t\tTimes(%d): sent %d\n", self->id, value);
   }
}
  */

  /*
void *merge (void *streams) {
   Stream *self = ((Args*)streams)->self;
   Stream *s1 = ((Args*)streams)->prod;
   Stream *s2 = (((Args*)streams)->prod)->next;
   void *a = get(s1);
   void *b = get(s2);

   while (1) {
      if (a < b) {
	 put(self, a);
	 a = get(s2);
	 printk(KERN_INFO "\t\t\t\t\tMerge(%d): sent %d from Times %d\n", 
		self->id, (int)a, s2->id);
      } else {
	 put(self, b);
	 b = get(s1);
	 printk(KERN_INFO "\t\t\t\t\tMerge(%d): sent %d from Times %d\n", 
		self->id, (int)b, s1->id);
      }
   }
}
  */

  /*
void *consumer (void *streams) {
   Stream *prod = ((Args*)streams)->prod;
   int i, value;
   
   for (i=0 ; i < 10 ; i++) 
      printk(KERN_INFO "\t\t\t\t\t\t\tConsumer: got %d\n", (int)get(prod));
}
  */

  /*
void init_stream (Args *args, Stream *self, void *data) {
   if (self != NULL) {
      self->available = 0;
      self->value = NULL;
      self->next = NULL;
      self->args = data;
      self->id = idcnt++;
      pthread_mutex_init(&self->lock, NULL);
      pthread_cond_init (&self->notifier, NULL);
   }
   args->self = self;
   args->prod = NULL;
}
  */

/* puts an initialized stream object onto the end of a streams input list */
  /*
void connect (Args *arg, Stream *s) {  
   s->next = arg->prod;
   arg->prod = s;
}
  */

struct task_struct *task;
int data;
int ret;
int thread_function(void *data) {
   int var;
   var = 10;
   return var;
}

static int kernel_init() {
   data = 20;
   printk(KERN_INFO"--------------------------------------------");
   task = kthread_create(&thread_function,(void *)data,"pradeep");
   task = kthread_run(&thread_function,(void *)data,"pradeep");
   printk(KERN_INFO"Kernel Thread : %s\n",task->comm);
   return 0;


   /*
   Stream suc1, suc2, tms1, tms2, mrg, cons;
   Args suc1_args, suc2_args, tms1_args, tms2_args, mrg_args, cons_args;

   init_stream(&suc1_args, &suc1, NULL);   /* initialize a successor stream */

   init_stream(&suc2_args, &suc2, NULL);   /* initialize a successor stream */

   init_stream(&tms1_args, &tms1, (void*)3); /* initialize a times 3 stream */
   connect(&tms1_args, &suc1);               /* connect to a successor */

   init_stream(&tms2_args, &tms2, (void*)5); /* initialize a times 5 stream */
   connect(&tms2_args, &suc2);               /* connect to a successor */

   init_stream(&mrg_args, &mrg, NULL);     /* initialize a merge stream */
   connect(&mrg_args, &tms1);              /* connect to a times stream */
   connect(&mrg_args, &tms2);              /* connect to a 2nd times stream */

   init_stream(&cons_args, NULL, NULL);    /* initialize a consumer stream */
   connect(&cons_args, &mrg);              /* connect to a merge stream */
   */
      
      /*
   kernel_create(&successor, (void*)&suc1_args, "succ_1");
   kernel_run(&successor, (void*)&suc1_args, "succ_1");
   kernel_create(&successor, (void*)&suc2_args, "succ_2");
   kernel_run(&successor, (void*)&suc2_args, "succ_2");
   kernel_create(&times, (void*)&tms1_args, "tms_1");
   kernel_run(&times, (void*)&tms1_args, "tms_1");
   kernel_create(&times, (void*)&tms2_args, "tms_2");
   kernel_run(&times, (void*)&tms2_args, "tms_2");
   kernel_create(&merge, (void*)&mrg_args, "mrg");
   kernel_run(&merge, (void*)&mrg_args, "mrg");
   kernel_create(&consumer, (void*)&cons_args, "consumer");
   kernel_run(&consumer, (void*)&cons_args, "consumer");
      */
}

static void kernel_exit() { }
   
module_init(kernel_init);
module_exit(kernel_exit);
